package me.zhengjie.pm.projectbase.service.impl;

import me.zhengjie.annotation.FieldMeta;
import me.zhengjie.pm.projectbase.domain.ProjectBase;
import me.zhengjie.utils.*;
import me.zhengjie.pm.projectbase.repository.ProjectBaseRepository;
import me.zhengjie.pm.projectbase.service.ProjectBaseService;
import me.zhengjie.pm.projectbase.service.dto.ProjectBaseDto;
import me.zhengjie.pm.projectbase.service.dto.ProjectBaseQueryCriteria;
import me.zhengjie.pm.projectbase.service.mapper.ProjectBaseMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
// 默认不使用缓存
//import org.springframework.cache.annotation.CacheConfig;
//import org.springframework.cache.annotation.CacheEvict;
//import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;

/**
* @author ZGZ
* @date 2020-04-14
*/
@Service
//@CacheConfig(cacheNames = "projectBase")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class ProjectBaseServiceImpl implements ProjectBaseService {

    private final ProjectBaseRepository projectBaseRepository;

    private final ProjectBaseMapper projectBaseMapper;

    public ProjectBaseServiceImpl(ProjectBaseRepository projectBaseRepository, ProjectBaseMapper projectBaseMapper) {
        this.projectBaseRepository = projectBaseRepository;
        this.projectBaseMapper = projectBaseMapper;
    }

    @Override
    //@Cacheable
    public Map<String,Object> queryAll(ProjectBaseQueryCriteria criteria, Pageable pageable){
        Page<ProjectBase> page = projectBaseRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        return PageUtil.toPage(page.map(projectBaseMapper::toDto));
    }

    @Override
    //@Cacheable
    public List<ProjectBaseDto> queryAll(ProjectBaseQueryCriteria criteria){
        return projectBaseMapper.toDto(projectBaseRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
    }

    @Override
    //@Cacheable(key = "#p0")
    public ProjectBaseDto findById(Integer id) {
        ProjectBase projectBase = projectBaseRepository.findById(id).orElseGet(ProjectBase::new);
        ValidationUtil.isNull(projectBase.getId(),"ProjectBase","id",id);
        return projectBaseMapper.toDto(projectBase);
    }

    @Override
    //@CacheEvict(allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    public ProjectBaseDto create(ProjectBase resources) {
        return projectBaseMapper.toDto(projectBaseRepository.save(resources));
    }

    @Override
    //@CacheEvict(allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    public void update(ProjectBase resources) {
        ProjectBase projectBase = projectBaseRepository.findById(resources.getId()).orElseGet(ProjectBase::new);
        ValidationUtil.isNull( projectBase.getId(),"ProjectBase","id",resources.getId());
        if (resources.getId()!= null){
            compareAndSaveChange(projectBase,resources);
        }
        projectBase.copy(resources);
        projectBase.equals(resources);
        projectBaseRepository.save(projectBase);
    }

    @Override
    //@CacheEvict(allEntries = true)
    public void deleteAll(Integer[] ids) {
        for (Integer id : ids) {
            projectBaseRepository.deleteById(id);
        }
    }

    @Override
    public void download(List<ProjectBaseDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (ProjectBaseDto projectBase : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("项目类型", projectBase.getProjectType());
            map.put("项目名称", projectBase.getProjectName());
            map.put("主管部门", projectBase.getDepartmentId());
            map.put("主管中心", projectBase.getCenterId());
            map.put("主管部门领导", projectBase.getDepartmentLeaderId());
            map.put("主管所领导", projectBase.getInstituteLeaderId());
            map.put("项目编号/核算码", projectBase.getProjectNo());
            map.put("密级", projectBase.getSecretLevel());
            map.put("重要程度", projectBase.getImportance());
            map.put("总体单位", projectBase.getMainCompany());
            map.put("研制内容", projectBase.getDevelopmentContents());
            map.put("项目工作文档位置", projectBase.getDocPath());
            map.put("项目代码位置", projectBase.getCodePath());
            map.put("项目开始时间", projectBase.getStartTime());
            map.put("项目结束时间", projectBase.getEndTime());
            map.put("项目所属计划类型", projectBase.getProjectPlanType());
            map.put("主要完成形式/成果", projectBase.getAchievement());
            map.put("计划开始时间", projectBase.getPlanStartTime());
            map.put("计划完成时间", projectBase.getPlanFinishTime());
            map.put("计划依据", projectBase.getPlanBasis());
            map.put("项目状态", projectBase.getProjectState());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public void compareAndSaveChange(ProjectBase oldInfo, ProjectBase nowInfo) {
        Map<String,String> changeMap = new HashMap<>();
        Class<?> oldClass = oldInfo.getClass();
        Class<?> newClass  = nowInfo.getClass();
        Field[] oldFields = oldClass.getDeclaredFields();
        Field[] newFields = newClass.getDeclaredFields();
        List<String> tempRs = new ArrayList<>();
        for (int i = 0; i < oldFields.length; i++) {
            if ("serialVersionUID".equals(oldFields[i].getName())) {
                continue;
            }
            oldFields[i].setAccessible(true);
            newFields[i].setAccessible(true);

            // 这样就获取到这个注解属性了
            FieldMeta fieldChinese = oldFields[i].getAnnotation(FieldMeta.class);
            //无对应注解则说明该字段无需比较
            if (fieldChinese == null || StringUtils.isBlank(fieldChinese.name())) {
                continue;
            }
            //获取注解中字段名
            String fieldName = fieldChinese.name();

            PropertyDescriptor oldPd = null;
            try {
                oldPd = new PropertyDescriptor(oldFields[i].getName(), oldClass);
                PropertyDescriptor newPd = new PropertyDescriptor(newFields[i].getName(), newClass);
                Method oldReadMethod = oldPd.getReadMethod();
                Method newReadMethod = newPd.getReadMethod();
                //获取对应字段的值
                Object oldValue = oldReadMethod.invoke(oldInfo);
                Object newValue = newReadMethod.invoke(nowInfo);
                tempRs = StringUtils.getDifferenceFieldStr(i, fieldName, oldValue, newValue);
//                System.out.println(tempRs);
            } catch (IntrospectionException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            /**获取差异字段*/
        }
    }
}